/******************************************************************************
 *  _____     _____
 *  \  __\    \  __\
 *   \ \_\\    \ \_\\
 *    \  __\SS  \  __\roject
 *     \_\       \_\
 *
 * Mateusz Maciąg, Rafał Urbański
 * Komputerowe Systemy Sterowania
 *****************************************************************************/

#ifndef SISOMODEL_H
#define SISOMODEL_H

#include "SimInterface/IConfigurable.h"
#include "SimInterface/ISimulator.h"

// Przestrzeń nazw
namespace RafMat
{
namespace SimEngine
{

/**
    Klasa reprezentująca model obiektu SISO, czyli z jednym wejściem
    i wyjściem.

    Klasa ta jest klasą abstrakcyjną. Każdy obiekt dynamiczny dziedziczy
    po tej klasie i implementuje metody związanie z symulacją.

    Przede wszystkim należy zaimplementować metodę simulateStep().
    Pozwala ona na pracę krokową, tzn. na daną próbkę wejściową, otrzymujemy
    jedną próbkę wyjściową. Funkcja realizuje całą dynamikę obiektu, tzn.
    może zmieniać jego stan wewnętrzny.

    Klasa dziedziczy po interfejsie IConfigurable z przestrzeni nazw SimInterface.
    Wiąże się to z implementacją metod getParameter, setParameter oraz
    dumpParameters. Jest to uogólniony sposób konfiguracji obiektu SISO.
    Przykładowo klasa DiscreteObject dziedzicząca po SISOModel implementuje
    funkcję setParameter, która potrafi zinterpretować przypisanie łańcuchowego
    parametru "apoly" z wartością "[2 4 6]".
*/
class SISOModel : public SimInterface::IConfigurable
{
public:
    /**
        Tworzy instancję obiektu SISO. Zadaniem konstruktora jest
        powiązanie obiektu z symulatorem. Jest to jedyny konstruktor
        w klasie, dlatego nie można utworzyć obiektu ot tak, swobodnego.

        Powiązanie z klasą symulatora jest konieczne ze względu na dostęp
        do parametrów symulatora (np. nr aktualnej próbki).

        \param [in] simulator Referencja do obiektu symulatora.
    */
    explicit SISOModel(const SimInterface::ISimulator& simulator)
        : m_simulator(simulator) {}

    /**
        Wersja konstruktora wymuszająca nadanie nazwy obiektowi w chwili
        tworzenia.
    */
    SISOModel(const SimInterface::ISimulator& simulator, std::string name)
            : IConfigurable(name), m_simulator(simulator) {}

    /**
        Zwraca obiekt symulatora, do którego należy ten obiekt SISO.

        \todo Może zmienić na wskaźniki shared_ptr?
        \return Obiekt symulatora-właściciela tego obiektu SISO.
    */
    const SimInterface::ISimulator& getSimulator() const { return m_simulator; }

    /**
        Wykonuje jeden krok symulacji.

        Metoda jest czysto wirtualna czyniąc klasę SISOModel abstrakcyjną.
        Zadaniem klas pochodnych jest implementacja metody wedle własnych
        potrzeb. Zasadą jest, że obiekt zachowuje się jak z jednym wejściem
        i jednym wejściem, tzn. przez parametr metody simulateStep rozumiemy
        próbkę wejściową, natomiast wartością zwracaną jest próbka wyjściowa.

        Implementator metody realizuje dynamikę (lub statykę) obiektu, z możliwością
        przechowywania stanu. Jeśli jest taka potrzeba można uzyskać dostęp
        do aktualnej próbki poprzez metodę getSimulator() oraz odpowiednie metody
        obiektu zwróconego.

        \param [in] inputSample Próbka wejściowa.
        \return Wartość wyjścia obiektu w bierzącym kroku.
    */
    virtual double simulateStep(double inputSample) = 0;

    /** Reset modelu do stanu początkowego */
    virtual void reset() = 0;

    // [deprecated] Wykorzystano w IConfigurable
    ///** Zapis parametrów do strumienia */
    //virtual void saveParams(std::ostream) = 0;

    ///** Odczyt parametrów ze strumienia */
    //virtual void loadParams(std::istream) = 0;

private:
    const SimInterface::ISimulator& m_simulator;      ///< Referencja do symulatora-właściciela obiektu.
};

}   // SimEngine namespace
}   // RafMat namespace

#endif // SISOMODEL_H
